/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.icee.myth.server.mail;

import com.icee.myth.common.messageQueue.DBMessageQueue;
import com.icee.myth.config.MapConfig;
import com.icee.myth.log.GameLogger;
import com.icee.myth.log.message.FileDebugGameLogMessage;
import com.icee.myth.log.message.GameLogMessage.GameLogType;
import com.icee.myth.log.message.builder.GameLogMessageBuilder;
import com.icee.myth.protobuf.builder.ClientToMapBuilder;
import com.icee.myth.protobuf.ExternalCommonProtocol.MailContentProto;
import com.icee.myth.protobuf.ExternalCommonProtocol.MailListProto;
import com.icee.myth.protobuf.ExternalCommonProtocol.MailNumProto;
import com.icee.myth.protobuf.ExternalCommonProtocol.MailProto;
import com.icee.myth.protobuf.InternalCommonProtocol.DBMailsProto;
import com.icee.myth.server.GameServer;
import com.icee.myth.server.actor.Human;
import com.icee.myth.server.message.dbMessage.builder.MapDBMessageBuilder;
import com.icee.myth.server.reward.CertainRewardInfo;
import com.icee.myth.utils.Consts;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;

/**
 *
 * @author liuxianke
 */
public class Mails {
    public enum MailsRefreshStatusType {
        MAIL_REFRESH_STATUS_NONE,
        MAIL_REFRESH_STATUS_REFRESHING,
        MAIL_REFRESH_STATUS_REFRESHED
    }
    public final TreeMap<Long, Mail> mails = new TreeMap<Long, Mail>();
    public final Human human;
    public long lastGlobalMaxMailId;
    public MailsRefreshStatusType refreshStatus;
    private LinkedList<Mail> cacheMails;
    private int unreadNum;
    private long nextAllowOperateTime;  // 下一次邮件操作许可时间（防止被攻击）

    public Mails(Human human, DBMailsProto mailsProto) {
        this.human = human;
        if (mailsProto != null) {
            refreshStatus = MailsRefreshStatusType.MAIL_REFRESH_STATUS_NONE;
            lastGlobalMaxMailId = mailsProto.getLastGlobalMaxMailId();
            List<MailProto> mailProtos = mailsProto.getMailsList();
            for (MailProto mailProto : mailProtos) {
                MailContentProto content = mailProto.getContent();
                CertainRewardInfo reward = content.hasReward()?new CertainRewardInfo(content.getReward()):null;
                int mailStatus = mailProto.getStatus();
                Mail mail = new Mail(mailProto.getMailId(),
                                     content.getTitle(),
                                     content.getDescription(),
                                     reward,
                                     mailStatus);
                mails.put(mail.id, mail);

                if (mailStatus == Consts.MAIL_STATUS_UNREAD) {
                    unreadNum++;
                }
            }
        } else {
            refreshStatus = MailsRefreshStatusType.MAIL_REFRESH_STATUS_REFRESHED;
        }
    }

    public DBMailsProto buildDBMailsProto() {
        DBMailsProto.Builder builder = DBMailsProto.newBuilder();
        if (refreshStatus == MailsRefreshStatusType.MAIL_REFRESH_STATUS_REFRESHED) {
            builder.setLastGlobalMaxMailId(GameServer.INSTANCE.lastMailId);
        } else {
            builder.setLastGlobalMaxMailId(lastGlobalMaxMailId);
        }

        for (Mail mail : mails.values()) {
            builder.addMails(mail.buildMailProto());
        }

        return builder.build();
    }

    public MailListProto buildMailListProto() {
        MailListProto.Builder builder = MailListProto.newBuilder();

        for (Mail mail : mails.values()) {
            builder.addMailBriefs(mail.buildMailBriefProto());
        }

        return builder.build();
    }

    public MailNumProto buildMailNumProto() {
        MailNumProto.Builder builder = MailNumProto.newBuilder();

        builder.setTotalNum(mails.size());
        builder.setUnreadNum(unreadNum);
        
        return builder.build();
    }

    // refresh方法在玩家进入游戏时调用
    public void refresh() {
        if (refreshStatus == MailsRefreshStatusType.MAIL_REFRESH_STATUS_NONE) {
            if (lastGlobalMaxMailId < GameServer.INSTANCE.lastMailId) {
                // 需要从数据库获取新补偿数据
                DBMessageQueue.queue().offer(MapDBMessageBuilder.buildGetNewMailDBMessage(human.id, lastGlobalMaxMailId));

                refreshStatus = MailsRefreshStatusType.MAIL_REFRESH_STATUS_REFRESHING;
            } else {
                // 不需要从数据库获取新补偿数据
                refreshStatus = MailsRefreshStatusType.MAIL_REFRESH_STATUS_REFRESHED;
            }
        }

        if (refreshStatus == MailsRefreshStatusType.MAIL_REFRESH_STATUS_REFRESHED) {
            // 向玩家发送补偿列表信息
            // 若补偿列表不为空，发给玩家客户端
            if (!mails.isEmpty()) {
                human.sendMessage(ClientToMapBuilder.buildMailNumChange(buildMailNumProto()));
            }
        }
    }

    public void refresh(LinkedList<Mail> newMails) {
        if (refreshStatus == MailsRefreshStatusType.MAIL_REFRESH_STATUS_REFRESHING) {
            if (cacheMails != null) {
                newMails.addAll(cacheMails);
                cacheMails = null;
            }

            // 加入到补偿列表中
            for (Mail mail : newMails) {
                if (mails.put(mail.id, mail) != null) {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + human.id + "] multi-add mail[" + mail.id + "]."));
                } else {
                    if (mail.status == Consts.MAIL_STATUS_UNREAD) {
                        unreadNum++;
                    }
                }
            }

            // 删除旧邮件
            while (mails.size() > MapConfig.INSTANCE.maxMailNum) {
                Mail removedMail = mails.remove(mails.firstKey());
                if (removedMail.status == Consts.MAIL_STATUS_UNREAD) {
                    unreadNum--;
                }
            }

            // 若玩家在线且补偿列表不为空，发给玩家客户端
            if (human.inGame) {
                if (!mails.isEmpty()) {
                    human.sendMessage(ClientToMapBuilder.buildMailNumChange(buildMailNumProto()));
                }
            }

            refreshStatus = MailsRefreshStatusType.MAIL_REFRESH_STATUS_REFRESHED;
        }
    }

    public void getList() {
        long currentTime = GameServer.INSTANCE.getCurrentTime();
        if (currentTime >= nextAllowOperateTime) {
            nextAllowOperateTime = currentTime + Consts.MILSECOND_1SECOND;  // cooldown 1 second
            human.sendMessage(ClientToMapBuilder.buildMailList(buildMailListProto()));
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + human.id + "] get mail list error because not cooldown."));
        }
    }

    /**
     *
     * @param mail
     * @param data 为群发补偿消息优化数据事先打包
     */
    public void addMail(Mail mail) {
        switch (refreshStatus) {
            case MAIL_REFRESH_STATUS_REFRESHING: {
                if (cacheMails == null) {
                    cacheMails = new LinkedList<Mail>();
                }
                cacheMails.add(mail);
                break;
            }
            case MAIL_REFRESH_STATUS_REFRESHED: {
                if (mails.put(mail.id, mail) == null) {
                    if (mail.status == Consts.MAIL_STATUS_UNREAD) {
                        unreadNum++;
                    }

                    // 删除旧补偿数据（注意：客户端要有相应的逻辑删除就补偿数据）
                    while (mails.size() > MapConfig.INSTANCE.maxMailNum) {
                        Mail removedMail = mails.remove(mails.firstKey());
                        if (removedMail.status == Consts.MAIL_STATUS_UNREAD) {
                            unreadNum--;
                        }
                    }

                    // 通知玩家邮件数改变
                    human.sendMessage(ClientToMapBuilder.buildMailNumChange(buildMailNumProto()));
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + human.id + "] multi-add mail[" + mail.id + "]."));
                }
                break;
            }
        }
    }

    public void getMailInfo(long mailId) {
        long currentTime = GameServer.INSTANCE.getCurrentTime();
        if (currentTime >= nextAllowOperateTime) {
            nextAllowOperateTime = currentTime + Consts.MILSECOND_1SECOND;  // cooldown 1 second
            Mail mail = mails.get(mailId);
            if (mail != null) {
                if (mail.status == Consts.MAIL_STATUS_UNREAD) {
                    mail.status = Consts.MAIL_STATUS_READED;
                    unreadNum--;

                    // 通知玩家邮件数改变
                    human.sendMessage(ClientToMapBuilder.buildMailNumChange(buildMailNumProto()));
                }

                // 发包通知客户端邮件详细信息
                human.sendMessage(ClientToMapBuilder.buildMailInfo(mail.buildMailProto()));
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + human.id + "] can't read mail[" + mailId + "] because mail not found."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + human.id + "] can't read mail[" + mailId + "] because not cooldown."));
        }
    }

    public void getReward(long mailId) {
        long currentTime = GameServer.INSTANCE.getCurrentTime();
        if (currentTime >= nextAllowOperateTime) {
            nextAllowOperateTime = currentTime + Consts.MILSECOND_1SECOND;  // cooldown 1 second
            if (refreshStatus == MailsRefreshStatusType.MAIL_REFRESH_STATUS_REFRESHED) {
                Mail mail = mails.get(mailId);
                if (mail != null) {
                    if (mail.status != Consts.MAIL_STATUS_GOTTEN) {
                        if (mail.reward != null) {
                            human.digestCertainReward(mail.reward, Consts.SOUL_CHANGE_LOG_TYPE_MAIL, (int)mailId);
                        }

                        if (mail.status == Consts.MAIL_STATUS_UNREAD) {
                            unreadNum--;

                            // 通知玩家邮件数改变
                            human.sendMessage(ClientToMapBuilder.buildMailNumChange(buildMailNumProto()));
                        }

                        mail.status = Consts.MAIL_STATUS_GOTTEN;

                        // 发包通知客户端邮件状态改变
                        human.sendMessage(ClientToMapBuilder.buildMailGotten(mailId));

                        // 记录行为日志
                        if (MapConfig.INSTANCE.useCYLog == true) {
                            List<String> cyLogList = new ArrayList<String>();
                            cyLogList.add("behaviorMC");
                            cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                            cyLogList.add("KDTY");
                            cyLogList.add(String.valueOf(human.id));
                            cyLogList.add(human.name);
                            cyLogList.add("");
                            cyLogList.add("HandleMailDBBehavior");
                            cyLogList.add(mailId + " ");
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                        }
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildHandleMailDBBehaviorGameLogMessage(human.id, mailId));
                    } else {
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                "Player[" + human.id + "] can't get mail[" + mailId + "] reward because mail has gotten."));
                    }
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + human.id + "] can't handle mail[" + mailId + "] because mail not found."));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + human.id + "] can't handle mail[" + mailId + "] because mail's status not refreshed."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + human.id + "] can't handle mail[" + mailId + "] because not cooldown."));
        }
    }

    public void removeMail(long mailId) {
        Mail removedMail = mails.remove(mailId);

        if (removedMail != null) {
            if (removedMail.status == Consts.MAIL_STATUS_UNREAD) {
                unreadNum--;
            }

            // 通知玩家邮件数改变
            human.sendMessage(ClientToMapBuilder.buildMailNumChange(buildMailNumProto()));

            // 发包通知客户端删除补偿条目
            human.sendMessage(ClientToMapBuilder.buildMailRemove(mailId));
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + human.id + "] can't delete mail[" + mailId + "] because mail not exist."));
        }
    }
}
